from PIL import Image, ImageTk
import pyautogui as pt
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox, filedialog
import subprocess
from bisect import *
import send2trash
import threading
import pystray
import windnd
import sys
import os
import time
import pygame
import requests
import tempfile
import io

# 获取屏幕尺寸
SCREEN_WIDTH, SCREEN_HEIGHT = pt.size()
taskbarHeight = 40
imgWidth, imgHeight = 200, 200
# 初始位置（右下角）
posX, posY = SCREEN_WIDTH - imgWidth, SCREEN_HEIGHT - imgHeight - taskbarHeight

root = tk.Tk()
root.geometry(f"{imgWidth}x{imgHeight}+{posX}+{posY}")
root.overrideredirect(True)
root.configure(bg='pink')
root.attributes('-transparentcolor', 'pink')
root.wm_attributes('-topmost', 1)

# 初始化pygame音频 - 优化参数确保流畅播放
pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=512)

tan = [
    -5.02733949212585,
    -1.49660576266549,
    -0.6681786379192988,
    -0.19891236737965837,
    0.198912367379658,
    0.6681786379192989,
    1.496605762665489,
    5.027339492125846
]


def resource_path(relative_path):
    """获取资源的绝对路径，兼容开发环境和打包后环境"""
    try:
        # 打包后的临时目录
        base_path = sys._MEIPASS
    except Exception:
        # 开发环境下的当前目录
        base_path = os.path.abspath(".")
    
    return os.path.join(base_path, relative_path)


def load_images(folder_path):
    image_list = []
    if not os.path.exists(folder_path):
        print(f"图片文件夹不存在: {folder_path}")
        return image_list
        
    for x in os.listdir(folder_path):
        try:
            file_path = os.path.join(folder_path, x)
            y = tk.PhotoImage(file=file_path)
            image_list.append(y)
        except Exception as e:
            print(f"加载图片失败 {file_path}: {e}")
    return image_list


class LuoHeiXiaoAI:
    """AI交互窗口类，现在嵌入到主程序中"""
    def __init__(self, parent, x_pos, y_pos, no_taskbar_icon=False):
        self.parent = parent
        self.root = tk.Toplevel(parent)
        self.root.title("罗小黑AI助手")
        # 窗口尺寸设置
        self.root.geometry(f"380x500+{x_pos}+{y_pos}")
        self.root.resizable(True, True)
        
        # 主题颜色配置
        self.bg_color = "#f0f7ff"
        self.dark_color = "#2c3e50"
        self.accent_color = "#3498db"
        self.light_color = "#ffffff"
        self.border_color = "#bdc3c7"
        self.root.configure(bg=self.bg_color)
        
        # 初始化pygame音频
        try:
            pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=512)
        except pygame.error as e:
            print(f"音频初始化错误: {e}")
            self.audio_available = False
        else:
            self.audio_available = True
        
        # 窗口关闭回调
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        
        # Windows任务栏图标设置
        if no_taskbar_icon and os.name == 'nt':
            self.root.attributes('-toolwindow', True)
            self.root.wm_attributes('-topmost', 1)
        
        # 字体配置
        self.font_config()
        
        # AI身份设置 - 罗小黑
        self.ai_identity = "你叫罗小黑，是一只可爱的黑色猫咪助手。你的性格活泼开朗。回答要简洁有趣，充满亲和力。不要说喵这个字了"
        
        # 初始化UI
        self.init_ui()
        
        # API配置
        self.chat_api_url = ""  #openai 接口地址 
        self.tts_api_url = ""  #文字转语言接口地址
        self.image_api_url = ""  #图片接口地址，暂未实现
        self.api_key = ""  #openai密钥
        
        # 状态变量
        self.is_thinking = False
        self.is_closing = False
        self.is_playing_audio = False
        self.audio_lock = threading.Lock()
        self.temp_audio_file = None
        self.image_window = None
        
        # 初始消息
        self.add_message("系统", "你好呀！我是罗小黑，有什么可以帮你的吗？😼")
        
    def font_config(self):
        """配置中文字体"""
        default_font = ("Microsoft YaHei", 10)
        title_font = ("Microsoft YaHei", 12, "bold")
        self.root.option_add("*Font", default_font)
        self.title_font = title_font
        
    def init_ui(self):
        """初始化用户界面"""
        # 主容器
        self.main_container = ttk.Frame(self.root, padding=10)
        self.main_container.pack(fill=tk.BOTH, expand=True)
        
        # 顶部区域
        self.top_frame = ttk.Frame(self.main_container, height=40)
        self.top_frame.pack(fill=tk.X, pady=(0, 10))
        self.top_frame.pack_propagate(False)
        
        # 顶部区域内容
        ttk.Label(
            self.top_frame, 
            text="😼 罗小黑AI助手", 
            font=self.title_font,
            foreground=self.accent_color,
            background=self.bg_color
        ).pack(side=tk.LEFT, padx=5, pady=5)
        
        # 分隔线
        ttk.Separator(self.main_container, orient='horizontal').pack(fill=tk.X, pady=(0, 10))
        
        # 聊天历史区域
        self.chat_frame = ttk.Frame(self.main_container, height=250)
        self.chat_frame.pack(fill=tk.BOTH, expand=False, pady=(0, 10))
        self.chat_frame.pack_propagate(False)

        # 聊天内容区域
        self.chat_history = scrolledtext.ScrolledText(
            self.chat_frame, 
            wrap=tk.WORD, 
            state=tk.DISABLED,
            bg=self.light_color,
            relief=tk.SUNKEN,
            bd=1,
            highlightthickness=1,
            highlightbackground=self.border_color
        )
        self.chat_history.pack(fill=tk.BOTH, expand=True)
        
        # 配置聊天区域样式
        self.chat_history.tag_config("sender", foreground=self.accent_color, font=("Microsoft YaHei", 10, "bold"))
        self.chat_history.tag_config("message", foreground=self.dark_color)
        self.chat_history.tag_config("error", foreground="#e74c3c")
        self.chat_history.tag_config("system", foreground="#9b59b6")
        
        # 输入区域
        self.input_frame = ttk.Frame(self.main_container, height=150)
        self.input_frame.pack(fill=tk.BOTH, expand=False)
        self.input_frame.pack_propagate(False)
        
        # 输入框容器
        input_container = ttk.Frame(self.input_frame)
        input_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 输入框
        self.user_input = scrolledtext.ScrolledText(
            input_container, 
            wrap=tk.WORD, 
            bg=self.light_color,
            relief=tk.SUNKEN,
            bd=1,
            highlightthickness=1,
            highlightbackground=self.border_color,
            highlightcolor=self.accent_color
        )
        self.user_input.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 8))
        self.user_input.focus_set()
        
        # 按钮区域
        button_frame = ttk.Frame(input_container)
        button_frame.pack(side=tk.RIGHT, pady=5)
        
        # 生成图像按钮
        self.image_btn = ttk.Button(
            button_frame, 
            text="生成图像", 
            command=self.generate_image,
            width=8
        )
        self.image_btn.pack(fill=tk.X, pady=(0, 4), ipady=3)
        
        # 发送按钮
        self.send_btn = ttk.Button(
            button_frame, 
            text="发送", 
            command=self.send_message,
            width=8
        )
        self.send_btn.pack(fill=tk.X, ipady=3)
        
        # 绑定Enter键发送消息，Shift+Enter换行
        self.user_input.bind("<Return>", lambda event: self.send_message() if not event.state & 0x10 else None)
        
    def add_message(self, sender, message):
        """添加消息到聊天记录"""
        self.chat_history.config(state=tk.NORMAL)
        self.chat_history.insert(tk.END, f"{sender}: ", "sender")
        self.chat_history.insert(tk.END, f"{message}\n\n", "message")
        self.chat_history.config(state=tk.DISABLED)
        self.chat_history.see(tk.END)
        
    def typewriter_effect(self, sender, full_text, index=0, delay=50):
        """打字机效果显示文本"""
        if index == 0:
            self.chat_history.config(state=tk.NORMAL)
            self.chat_history.insert(tk.END, f"{sender}: ", "sender")
            self.chat_history.config(state=tk.DISABLED)
        
        if index < len(full_text):
            self.chat_history.config(state=tk.NORMAL)
            self.chat_history.insert(tk.END, full_text[index], "message")
            self.chat_history.config(state=tk.DISABLED)
            self.chat_history.see(tk.END)
            self.root.after(delay, self.typewriter_effect, sender, full_text, index + 1, delay)
        else:
            self.chat_history.config(state=tk.NORMAL)
            self.chat_history.insert(tk.END, "\n\n")
            self.chat_history.config(state=tk.DISABLED)
            # 恢复状态
            self.is_thinking = False
            self.send_btn.config(state=tk.NORMAL, text="发送")
            self.image_btn.config(state=tk.NORMAL)
        
    def send_message(self):
        """发送消息并获取回复"""
        if self.is_thinking:
            messagebox.showinfo("提示", "罗小黑正在思考中，请稍候...")
            return
            
        user_message = self.user_input.get("1.0", tk.END).strip()
        if not user_message:
            return
            
        # 清空输入框
        self.user_input.delete("1.0", tk.END)
        
        # 添加用户消息
        self.add_message("你", user_message)
        
        # 更新状态
        self.is_thinking = True
        self.send_btn.config(state=tk.DISABLED, text="思考中...")
        self.image_btn.config(state=tk.DISABLED)
        
        # 新线程处理AI回复
        threading.Thread(
            target=self.get_ai_response, 
            args=(user_message,),
            daemon=True
        ).start()
        
    def get_ai_response(self, user_message):
        """获取AI回复"""
        if self.is_closing:
            return
            
        try:
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {self.api_key}"
            }
            
            data = {
                "model": "gpt-3.5-turbo",
                "messages": [
                    {"role": "system", "content": self.ai_identity},
                    {"role": "user", "content": user_message}
                ],
                "temperature": 0.8
            }
            
            response = requests.post(
                self.chat_api_url,
                json=data,
                headers=headers,
                timeout=60
            )
            response.raise_for_status()
            
            result = response.json()
            
            if result.get("choices") and len(result["choices"]) > 0:
                ai_response = result["choices"][0]["message"]["content"]
                self.root.after(0, self.typewriter_effect, "罗小黑", ai_response)
                
                # 音频回复
                if self.audio_available:
                    self.get_tts_audio(ai_response)
                else:
                    self.root.after(0, lambda: self.add_message("系统", "音频功能不可用"))
            else:
                ai_response = "抱歉，没能理解你的意思呢"
                self.root.after(0, self.update_ai_response, ai_response)
                
        except Exception as e:
            error_msg = f"获取回复失败: {str(e)}"
            self.root.after(0, self.add_message, "系统", error_msg)
        finally:
            # 恢复状态
            self.root.after(0, lambda: setattr(self, 'is_thinking', False))
            self.root.after(0, lambda: self.send_btn.config(state=tk.NORMAL, text="发送"))
            self.root.after(0, lambda: self.image_btn.config(state=tk.NORMAL))
            
    def get_tts_audio(self, text):
        """获取文字转语音"""
        if self.is_closing:
            return
            
        try:
            params = {
                "type": "baidu",
                "msg": text,
                "id": "4148"
            }
            
            response = requests.get(
                self.tts_api_url,
                params=params,
                timeout=30
            )
            response.raise_for_status()
            
            result = response.json()
            
            if result.get("code") == 200 and "tts" in result:
                audio_url = result["tts"]
                self.root.after(0, lambda: self.play_audio(audio_url))
            else:
                error_msg = f"语音合成失败: {result.get('msg', '未知错误')}"
                self.root.after(0, self.add_message, "系统", error_msg)
                
        except Exception as e:
            error_msg = f"获取音频失败: {str(e)}"
            self.root.after(0, self.add_message, "系统", error_msg)
    
    def play_audio(self, audio_url):
        """播放音频"""
        with self.audio_lock:
            if self.is_playing_audio:
                pygame.mixer.music.stop()
                self.cleanup_temp_audio()
                
            self.is_playing_audio = True
            
            try:
                # 下载音频
                response = requests.get(audio_url, timeout=30)
                response.raise_for_status()
                
                # 创建临时文件
                with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as f:
                    f.write(response.content)
                    self.temp_audio_file = f.name
                
                # 播放
                pygame.mixer.music.load(self.temp_audio_file)
                pygame.mixer.music.play()
                
                # 监控播放状态
                while pygame.mixer.music.get_busy() and not self.is_closing:
                    time.sleep(0.1)
                    
            except Exception as e:
                error_msg = f"音频播放失败: {str(e)}"
                self.root.after(0, self.add_message, "系统", error_msg)
            finally:
                self.cleanup_temp_audio()
                self.is_playing_audio = False
    
    def cleanup_temp_audio(self):
        """清理临时音频文件"""
        if self.temp_audio_file and os.path.exists(self.temp_audio_file):
            try:
                pygame.mixer.music.unload()
                os.remove(self.temp_audio_file)
            except Exception as e:
                print(f"清理临时文件失败: {e}")
            finally:
                self.temp_audio_file = None
    
    def generate_image(self):
        """生成图像"""
        prompt = self.user_input.get("1.0", tk.END).strip()
        if not prompt:
            messagebox.showinfo("提示", "请输入图像描述后再生成哦~")
            return
            
        # 清空输入框
        self.user_input.delete("1.0", tk.END)
        
        # 添加记录
        self.add_message("你", f"生成图像: {prompt}")
        self.add_message("罗小黑", "正在努力生成图像中，请稍候 🎨")
        
        # 禁用按钮
        self.send_btn.config(state=tk.DISABLED)
        self.image_btn.config(state=tk.DISABLED)
        
        # 新线程处理
        threading.Thread(
            target=self.process_image_generation, 
            args=(prompt,),
            daemon=True
        ).start()
    
    def process_image_generation(self, prompt):
        """处理图像生成请求"""
        if self.is_closing:
            return
            
        try:
            headers = {
                "Content-Type": "application/json",
                "Authorization": f"Bearer {self.api_key}"
            }
            
            data = {
                "prompt": prompt,
                "n": 1,
                "size": "256x256"
            }
            
            response = requests.post(
                self.image_api_url,
                json=data,
                headers=headers,
                timeout=120
            )
            response.raise_for_status()
            
            result = response.json()
            
            if result.get("data") and len(result["data"]) > 0:
                image_url = result["data"][0]["url"]
                self.root.after(0, lambda: self.display_image(image_url, prompt))
            else:
                self.root.after(0, lambda: self.add_message("罗小黑", "抱歉，没能生成图像呢"))
                
        except Exception as e:
            error_msg = f"图像生成失败: {str(e)}"
            self.root.after(0, self.add_message, "系统", error_msg)
        finally:
            # 恢复按钮状态
            self.root.after(0, lambda: self.send_btn.config(state=tk.NORMAL))
            self.root.after(0, lambda: self.image_btn.config(state=tk.NORMAL))
    
    def display_image(self, image_url, prompt):
        """显示生成的图像"""
        try:
            # 下载图像
            response = requests.get(image_url, timeout=30)
            response.raise_for_status()
            
            # 打开图像
            image_data = response.content
            image = Image.open(io.BytesIO(image_data))
            
            # 创建新窗口显示图像
            self.image_window = tk.Toplevel(self.root)
            self.image_window.title(f"生成的图像: {prompt[:30]}...")
            self.image_window.geometry(f"{image.width}x{image.height+50}")
            
            # 转换为Tkinter可用格式
            tk_image = ImageTk.PhotoImage(image)
            
            # 显示图像
            image_label = ttk.Label(self.image_window, image=tk_image)
            image_label.image = tk_image  # 保持引用
            image_label.pack(pady=10)
            
            # 保存按钮
            save_btn = ttk.Button(
                self.image_window,
                text="保存图像",
                command=lambda: self.save_image(image_data, prompt)
            )
            save_btn.pack(pady=10)
            
            self.add_message("罗小黑", "图像生成好啦，快看看吧 😊")
            
        except Exception as e:
            error_msg = f"图像显示失败: {str(e)}"
            self.root.after(0, self.add_message, "系统", error_msg)
    
    def save_image(self, image_data, prompt):
        """保存图像到本地"""
        try:
            # 生成默认文件名
            default_filename = f"luo_heixiao_image_{int(time.time())}.png"
            
            # 打开文件对话框
            file_path = filedialog.asksaveasfilename(
                defaultextension=".png",
                filetypes=[("PNG files", "*.png"), ("All files", "*.*")],
                initialfile=default_filename
            )
            
            if file_path:
                # 保存图像
                with open(file_path, "wb") as f:
                    f.write(image_data)
                self.add_message("系统", f"图像已保存到: {file_path}")
                
        except Exception as e:
            error_msg = f"图像保存失败: {str(e)}"
            self.root.after(0, self.add_message, "系统", error_msg)
    
    def update_ai_response(self, ai_response):
        """更新AI回复"""
        self.add_message("罗小黑", ai_response)
        self.is_thinking = False
        self.send_btn.config(state=tk.NORMAL, text="发送")
        self.image_btn.config(state=tk.NORMAL)
    
    def on_close(self):
        """关闭窗口处理"""
        self.is_closing = True
        
        # 清理音频资源
        with self.audio_lock:
            if self.is_playing_audio:
                pygame.mixer.music.stop()
            self.cleanup_temp_audio()
        
        if self.audio_available:
            pygame.mixer.quit()
            
        # 关闭图像窗口
        if self.image_window and isinstance(self.image_window, tk.Toplevel):
            self.image_window.destroy()
            
        # 通知主程序AI窗口已关闭
        if hasattr(self.parent, 'pet'):
            self.parent.pet.ai_window_open = False
            
        self.root.destroy()


class Pet:
    def __init__(self, player):
        self.shellPath = resource_path('')
        self.eyes = load_images(resource_path(os.path.join('src', 'eyes')))
        self.tails = load_images(resource_path(os.path.join('src', 'tails')))
        self.eat = load_images(resource_path(os.path.join('src', 'eat')))
        self.click = load_images(resource_path(os.path.join('src', 'click')))

        self.len_eyes = len(self.eyes)
        self.len_tails = len(self.tails)
        self.player = player
        self.eyes_times = 0
        self.topWindow = None
        self.audio_lock = threading.Lock()  # 音频播放锁，解决不流畅问题
        self.is_playing = False  # 音频播放状态标记
        self.is_visible = True  # 宠物可见状态
        self.systray_menu = None  # 系统托盘菜单
        
        # 初始化AI窗口状态跟踪属性
        self.ai_window = None  # 存储AI窗口实例
        self.ai_window_open = False  # AI窗口是否打开的标志
        
        self._systray()  # 初始化系统托盘
        self.iconDir = {}

        # 音频配置
        self.audio_file = resource_path('lj.mp3')
        if not pygame.mixer.get_init():
            pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=512)

    # 音频播放逻辑
    def _play_audio(self, force_restart=False):
        """播放本地lj.mp3音频文件"""
        with self.audio_lock:
            if self.is_playing and not force_restart:
                print("正在播放音频，忽略新请求")
                return
            self.is_playing = True

        try:
            # 检查音频文件是否存在
            if not os.path.exists(self.audio_file):
                print(f"错误: 未找到音频文件 {self.audio_file}")
                return

            # 确保pygame初始化正确
            if not pygame.mixer.get_init():
                pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=512)
            
            # 停止任何正在播放的音频
            if pygame.mixer.music.get_busy():
                pygame.mixer.music.stop()
                
            # 加载并播放音频
            pygame.mixer.music.load(self.audio_file)
            pygame.mixer.music.play()

            # 循环检查播放状态
            while pygame.mixer.music.get_busy():
                time.sleep(0.05)

        except Exception as e:
            print(f"音频播放失败: {e}")

        finally:
            with self.audio_lock:
                self.is_playing = False

    # 位置计算逻辑
    def _calculate_nearby_position(self, offset_x, offset_y, width, height):
        """计算在宠物附近的位置，确保窗口完全显示在屏幕内"""
        # 基础位置：宠物当前位置 + 偏移量
        base_x = posX + offset_x
        base_y = posY + offset_y
        
        # 确保窗口不会超出屏幕边界
        if base_x + width > SCREEN_WIDTH:
            base_x = SCREEN_WIDTH - width
        if base_x < 0:
            base_x = 0
        if base_y + height > SCREEN_HEIGHT:
            base_y = SCREEN_HEIGHT - height
        if base_y < 0:
            base_y = 0
            
        return base_x, base_y

    # AI交互窗口
    def _open_ai_window(self, event=None):
        """打开AI交互窗口（现在直接创建窗口实例，不再启动新进程）"""
        if self.ai_window_open:
            print("AI窗口已经打开，不创建新窗口")
            return
            
        try:
            # 计算AI窗口位置
            ai_x, ai_y = self._calculate_nearby_position(
                imgWidth + 10 if posX + imgWidth + 400 < SCREEN_WIDTH else -400 - 10,
                0, 400, 500
            )
            
            # 直接创建AI窗口实例（关键修改：不再运行外部Python文件）
            self.ai_window = LuoHeiXiaoAI(
                self.player, 
                ai_x, 
                ai_y, 
                no_taskbar_icon=True
            )
            
            self.ai_window_open = True
            
            # 监控AI窗口是否关闭
            def monitor_ai_window():
                while self.ai_window_open:
                    if not hasattr(self.ai_window, 'root') or not self.ai_window.root.winfo_exists():
                        self.ai_window_open = False
                        break
                    time.sleep(0.5)
            
            threading.Thread(target=monitor_ai_window, daemon=True).start()
            
        except Exception as e:
            print(f"打开AI窗口失败: {e}")
            self.ai_window_open = False

    # 系统托盘
    def _update_systray_menu(self):
        """根据宠物可见状态更新系统托盘菜单"""
        visibility_item = pystray.MenuItem(
            '隐藏宠物' if self.is_visible else '显示宠物',
            self._toggle_visibility
        )
        
        # AI对话菜单项状态根据AI窗口是否打开动态调整
        ai_menu_state = pystray.MenuItem(
            'AI对话 (已打开)' if self.ai_window_open else 'AI对话',
            self._open_ai_window,
            enabled=not self.ai_window_open  # 窗口打开时禁用菜单
        )
        
        # 重新创建菜单
        self.systray_menu = (
            visibility_item,
            pystray.MenuItem('播放声音', lambda: threading.Thread(
                             target=self._play_audio, daemon=True).start()),
            ai_menu_state,
            pystray.Menu.SEPARATOR,
            pystray.MenuItem('关于', self._show_about),
            pystray.MenuItem('退出', self._quit)
        )
        
        # 更新托盘图标菜单
        if hasattr(self, 'icon') and self.icon is not None:
            self.icon.menu = self.systray_menu

    def _toggle_visibility(self):
        """切换宠物显示/隐藏状态"""
        if self.is_visible:
            self._hide_window()
        else:
            self._show_window()
        self._update_systray_menu()

    def _systray(self):
        """初始化系统托盘"""
        self._update_systray_menu()  # 初始化菜单
        
        # 检查系统托盘图标路径
        icon_path = resource_path(os.path.join('src', 'misc', 'icon.png'))
        if not os.path.exists(icon_path):
            print(f"警告: 系统托盘图标缺失：{icon_path}（将使用默认图标）")
            image = Image.new('RGB', (64, 64), color='red')
        else:
            try:
                image = Image.open(icon_path)
            except Exception as e:
                print(f"加载系统托盘图标失败: {e}")
                image = Image.new('RGB', (64, 64), color='red')
                
        self.icon = pystray.Icon("icon", image, "桌面宠物", self.systray_menu)
        # 启动托盘线程
        threading.Thread(target=self.icon.run, daemon=True).start()

    def _show_about(self):
        """显示关于对话框"""
        about_dialog = tk.Toplevel(self.player)
        about_dialog.title("关于")
        about_dialog.geometry("200x120")
        about_dialog.resizable(False, False)
        about_dialog.wm_attributes('-topmost', 1)
        
        # 计算居中位置
        x = posX + (imgWidth - 200) // 2
        y = posY + (imgHeight - 120) // 2
        about_dialog.geometry(f"200x120+{x}+{y}")
        
        tk.Label(about_dialog, text="桌面宠物 v1.0", font=("SimHei", 12, "bold")).pack(pady=10)
        tk.Label(about_dialog, text="一个可爱的桌面宠物程序", font=("SimHei", 10)).pack(pady=5)
        ttk.Button(about_dialog, text="确定", command=about_dialog.destroy).pack(pady=10)

    def _eyes_play(self, element) -> None:
        x, y = pt.position()
        if posX < x < posX + imgWidth and posY < y < posY + imgHeight:
            img_num = 0
        else:
            if x == posX:
                img_num = 5
            else:
                tan_theta = -(y - posY) / (x - posX)
                if tan_theta >= tan[7] or tan_theta < tan[0]:
                    img_num = 5
                else:
                    img_num = (bisect_left(tan, tan_theta) + 4) % 8 + 1

            if img_num == 1:
                if x < posX:
                    img_num += 8
            else:
                if y < posY:
                    img_num += 8
        
        if 0 <= img_num < len(self.eyes):
            img = self.eyes[img_num]
            element.config(image=img)
        
        self.eyes_times += 1
        root.after(50, lambda: self._eyes_play(element))

    def _tails_play(self, element, index: int = 0) -> None:
        if index >= self.len_tails:
            index = 0
            
        img = self.tails[index]
        element.config(image=img)
        
        if index == 0:
            root.after(1000, lambda: self._tails_play(element, index + 1))
        else:
            root.after(200, lambda: self._tails_play(element, index + 1))

    def _trigger_animation(self):
        """触发宠物点击动画"""
        if self.topWindow and isinstance(self.topWindow, tk.Label) and self.topWindow.winfo_exists():
            return
            
        self.topWindow = tk.Label(self.player, bg='pink', bd=0)
        self.topWindow.place(relx=0, rely=0, relwidth=1, relheight=1)
        self._play_once(self.topWindow, self.click)

    def _play_once(self, window, images, index: int = 0):
        if index >= len(images):
            window.destroy()
            self.topWindow = None
            return
            
        img = images[index]
        window.config(image=img)
        root.after(100, lambda: self._play_once(window, images, index + 1))

    def _ondrop(self, paths_raw) -> None:
        self.topWindow = tk.Label(self.player, bg='pink', bd=0)
        self.topWindow.place(relx=0, rely=0, relwidth=1, relheight=1)
        self._play_once(self.topWindow, self.eat)
        threading.Thread(target=self._move2trash, args=(paths_raw,)).start()

    def _move2trash(self, paths_raw) -> None:
        try:
            paths = [x.decode('gbk') for x in paths_raw]
            for path in paths:
                send2trash.send2trash(path)
        except Exception as e:
            print(f"移动文件到回收站失败: {e}")

    def _getPoint(self, event):
        self.x, self.y = event.x, event.y

    def _move(self, event):
        global posX, posY
        new_x = (event.x - self.x) + self.player.winfo_x()
        new_y = (event.y - self.y) + self.player.winfo_y()
        s = f"{imgWidth}x{imgHeight}+{new_x}+{new_y}"
        posX = new_x
        posY = new_y
        
        self.player.geometry(s)

    def _hide_window(self):
        # 隐藏前关闭所有窗口
        if self.topWindow and isinstance(self.topWindow, tk.Label) and self.topWindow.winfo_exists():
            self.topWindow.destroy()
            self.topWindow = None
        self.player.withdraw()
        self.is_visible = False

    def _show_window(self):
        self.player.deiconify()
        self.is_visible = True

    def _quit(self, icon=None):
        # 退出前关闭所有窗口
        if self.topWindow and isinstance(self.topWindow, tk.Label) and self.topWindow.winfo_exists():
            self.topWindow.destroy()
            
        # 如果AI窗口打开，关闭它
        if self.ai_window_open and self.ai_window:
            try:
                self.ai_window.on_close()
            except Exception as e:
                print(f"关闭AI窗口失败: {e}")
                
        if icon:
            icon.stop()
            
        # 清理资源
        pygame.mixer.quit()
        self.player.quit()
        self.player.destroy()
        sys.exit()

    def _on_left_click(self, event):
        """左键单击触发宠物动画"""
        self._trigger_animation()

    def _on_left_double_click(self, event):
        """左键双击强制重新播放音频"""
        threading.Thread(target=self._play_audio, args=(True,), daemon=True).start()
        return "break"

    def play(self):
        eye = tk.Label(self.player, bg='pink', bd=0)
        eye.place(relx=0.145, rely=0.105, relwidth=0.71, relheight=0.5)
        tail = tk.Label(self.player, bg='pink', bd=0)
        tail.place(relx=0.145, rely=0.605, relwidth=0.71, relheight=0.29)
        
        self._tails_play(tail)
        self._eyes_play(eye)
        
        # 绑定鼠标事件
        self.player.bind("<Button-1>", self._getPoint)          # 左键点击获取位置（用于拖动）
        self.player.bind("<B1-Motion>", self._move)             # 左键拖动
        self.player.bind("<ButtonRelease-1>", self._on_left_click)  # 左键单击：触发动画
        self.player.bind("<Double-Button-1>", self._on_left_double_click)  # 左键双击：播放音频
        self.player.bind("<Button-3>", self._open_ai_window)     # 右键单击：打开AI对话框
        self.player.bind("<Double-Button-3>", self._open_ai_window)  # 右键双击：打开AI对话框
        
        # 绑定拖放事件
        windnd.hook_dropfiles(self.player, func=self._ondrop)


# 启动应用
if __name__ == "__main__":
    # 将宠物实例附加到root窗口，方便AI窗口访问
    root.pet = Pet(root)
    root.pet.play()
    root.mainloop()

